/*-------------------------------------------------------------------------
| TStaticArray:
| ------------
| 
|---------------------------------------------------------------------------*/
template<typename T, uint N>
class TStaticArray : public THandlePtr
{
protected:
	T mStore[N];
public:
	TStaticArray(void) : THandlePtr()
	{
	}

	TStaticArray(T value) : THandlePtr()
	{
		SetEach(value);
	}

	void SetEach(T value)
	{
		for(uint i=0; i!=N; ++i)
		{
			mStore[i]=value;
		}
	}
	T& operator[](uint index)
	{
		return mStore[index];
	}
	T operator[](uint index) const
	{
		return mStore[index];
	}
	T& Get(uint index)
	{
		return mStore[index];
	}
	const T Get(uint index) const
	{
		return mStore[index];
	}

	T* GetMemory(void)
	{
		return mStore;
	}

	virtual UnSafeConstPtr GetPointer(void) const
	{
		return static_cast<UnSafeConstPtr>(&mStore[0]);
	}
};

/*-------------------------------------------------------------------------
| StaticArray:
| ------------
| 
|---------------------------------------------------------------------------*/
template<typename T, uint N>
class StaticArray : public ref<TStaticArray<T, N> >
{
	typedef ref<TStaticArray<T, N> > Base;
public:
	StaticArray() : Base() {}
	StaticArray(ref<TStaticArray<T, N> > copy) : Base(copy) {} // for Cast

	T& operator [](int index)
	{
		return Base::mReference->Get(index);
	}

	using Base::operator =;
};

/*-------------------------------------------------------------------------
| TDynamicArray:
| ------------
| 
|---------------------------------------------------------------------------*/
template<typename T>
class TDynamicArray : public THandleBindPtr<T*>
{
	typedef THandleBindPtr<T*> Base;
protected:
	uint mSize;
public:
	explicit TDynamicArray(uint size) : Base(new T[mSize = size])
	{
	}
	virtual ~TDynamicArray(void)
	{
		delete[] Base::mHandle;
	}
	T& operator[](uint index)
	{
		return Base::mHandle[index];
	}
	T operator[](uint index) const
	{
		return Base::mHandle[index];
	}
	T& Get(uint index)
	{
		return Base::mHandle[index];
	}
	const T Get(uint index) const
	{
		return Base::mHandle[index];
	}
	uint Size(void) const
	{
		return mSize;
	}

	T* GetMemory(void)
	{
		return Base::mHandle;
	}

	const T* GetMemory(void) const
	{
		return Base::mHandle;
	}
};

/*-------------------------------------------------------------------------
| DynamicArray:
| ------------
| 
|---------------------------------------------------------------------------*/
template<typename T>
class DynamicArray : public ref<TDynamicArray<T> >
{
	typedef ref<TDynamicArray<T> > Base;
public:
	DynamicArray() : Base() {}
	DynamicArray(ref<TDynamicArray<T> > copy) : Base(copy) {} // for Cast

	T& operator [](int index)
	{
		return Base::mReference->Get(index);
	}
	using Base::operator =;

	template<typename TCast>
	inline ref<TCast> As(void)
	{
		//for cast null don't check ptr : CheckPtr(mReference);
		return static_cast<TCast*>(Base::mReference);
	}
};

/*-------------------------------------------------------------------------
| TArrayAllocation:
| ------------
| Base allocator class
---------------------------------------------------------------------------*/
template<typename T, int TQuickBufferSize = 32, int TCapacity = 32>
class TArrayAllocation : public TObject
{
private:
	void Dispose(void);
public:
	enum
	{
		QuickBufferSize = TQuickBufferSize,
		Capacity = TCapacity
	};

	TArrayAllocation() : TObject(), mBuffer(0), mSize(0), mLength(0) {}
	virtual ~TArrayAllocation()
	{
		Dispose();
	}
	uint						Length() const;
	uint						Size() const;
	bool						Empty() const;
public:
	virtual void				Clear(void);
	virtual uint				SetLength(unsigned int dSize);
protected:
	bool						IsUsingQuickBuffer(void) const;
	void						Move(const T* in, T* out, uint len);
protected:
	T*		mBuffer;
	uint	mSize;
	uint	mLength;
	T		mQuickBuffer[QuickBufferSize];
};

template<typename T>
class TArrayRefStrategy : public TArrayAllocation<T>
{
	typedef TArrayAllocation<T> Base;
public:
	inline void DisposeItem(T& item)
	{
		item = NullPtr;
	}

	inline void DisposeItems()
	{
		for (uint i = 0; i!=Base::Length(); ++i)
		{
			DisposeItem(Base::mBuffer[i]);
		}
	}
};

template<typename T>
class TArrayPODStrategy : public TArrayAllocation<T>
{
public:
	inline void DisposeItem(T& item)
	{
		// POD-type didn't dispose
	}

	void DisposeItems()
	{
		// POD-type didn't dispose
	}
};

/*-------------------------------------------------------------------------
| Array:
| ------------
| Provides methods for creating, manipulating, searching, and sorting arrays,
| thereby serving as the base class for all arrays in the common language runtime.
---------------------------------------------------------------------------*/
template<typename T, typename TStrategy = TArrayRefStrategy<T> >
class TArray : public TStrategy
{
	typedef TStrategy Base;
public:
	TArray(void);

	virtual ~TArray(void)
	{
		Base::DisposeItems();
	}

	inline T& Get(uint index)
	{
		CheckPtr(Base::mBuffer);
		return Base::mBuffer[index];
	}

	inline T& Add(T item)
	{
		//lock(this);
		CheckPtr(Base::mBuffer);
		return Base::mBuffer[SetLength(Base::Length()+1)-1] = item;
	}

	inline void Pop()
	{
		DisposeItem(Back());
		SetLength(Base::Length() - 1);
	}

	inline T& Back()
	{
		return Base::mBuffer[Base::Length()-1];
	}

	inline T Find(ref<IComparer<T> > cmp)
	{
		for(Iterator it = Begin(), end = End(); it!=end; ++it)
		{
			if(cmp->Compare(*it))
			{
				return *it;
			}
		}
		return NullPtr;
	}

	virtual void Clear(void)
	{
		Base::DisposeItems();
		Base::Clear();
	}
public:
	/*-------------------------------------------------------------------------
	| Iterator:
	| ------------
	| Helper for enumerable class
	---------------------------------------------------------------------------*/
	class Iterator
	{
	public:
		Iterator(ref<TArray> src, uint index)
			:  mSource(src), mIndex(index)
		{}

		bool operator !=(const Iterator& it)
		{
			return(mIndex != it.mIndex);
		}

		Iterator& operator ++(void)
		{
			++mIndex;
			return *this;
		}

		T& operator*()
		{
			return mSource->Get(mIndex);
		}

		T& operator->()
		{
			return mSource->Get(mIndex);
		}
	private:
		ref<TArray> mSource;
		uint mIndex;
	};

	Iterator Begin(void)
	{
		return Iterator(this, 0);
	}

	Iterator End(void)
	{
		return Iterator(this, Base::Length());
	}

private:
};

/*-------------------------------------------------------------------------
| Array:
| ------------
| Provides methods for creating, manipulating, searching, and sorting arrays,
| thereby serving as the base class for all arrays in the common language runtime.
---------------------------------------------------------------------------*/
template<typename T, typename TStrategy = TArrayRefStrategy<T> >
class Array : public ref<TArray<T, TStrategy> >
{
	typedef ref<TArray<T, TStrategy> > Base;
public:
	typedef typename TArray<T, TStrategy>::Iterator Iterator;
	inline Array(void) : Base() {}
	inline Array(ref<TArray<T, TStrategy> > copy) : Base(copy) {} // for Cast

	inline T& operator [](int index)
	{
		return Base::mReference->Get(index);
	}
};

/*-------------------------------------------------------------------------
| ArrayPOD:
| ------------
| Provides methods for creating, manipulating, searching, and sorting arrays,
| thereby serving as the base class for all arrays in the common language runtime.
---------------------------------------------------------------------------*/
template<typename T, typename TStrategy = TArrayPODStrategy<T> >
class ArrayPOD : public ref<TArray<T, TStrategy> >
{
	typedef ref<TArray<T, TStrategy> > Base;
public:
	typedef typename TArray<T, TStrategy>::Iterator Iterator;
	inline ArrayPOD(void) : Base() {}
	inline ArrayPOD(ref<TArray<T, TStrategy> > copy) : Base(copy) {} // for Cast

	inline T& operator [](int index)
	{
		return Base::mReference->Get(index);
	}
};

/*-----------------------------------------------------------------------------
Implementation
-------------------------------------------------------------------------------*/

/*-------------------------------------------------------------------------
| TArrayAllocation:
---------------------------------------------------------------------------*/
template<typename T, int QuickBufferSize, int Capacity>
inline void TArrayAllocation<T, QuickBufferSize, Capacity>::Dispose()
{
	if(!IsUsingQuickBuffer())
	{
		delete[] mBuffer;
	}
	//rebind to quick
	mSize = QuickBufferSize;
	mBuffer = mQuickBuffer;

	mLength = 0;
}

template<typename T, int QuickBufferSize, int Capacity>
inline void TArrayAllocation<T, QuickBufferSize, Capacity>::Clear()
{
	Dispose();
}

template<typename T, int QuickBufferSize, int Capacity>
inline bool TArrayAllocation<T, QuickBufferSize, Capacity>::IsUsingQuickBuffer() const
{
	return !(mSize > QuickBufferSize);
}

template<typename T, int QuickBufferSize, int Capacity>
inline void TArrayAllocation<T, QuickBufferSize, Capacity>::Move(const T* in, T* out, uint len)
{
	for(uint i = 0; i != len; ++i)
		out[i] = in[i];
}

template<typename T, int QuickBufferSize, int Capacity>
inline unsigned int TArrayAllocation<T, QuickBufferSize, Capacity>::SetLength(uint size)
{
	if(!(mSize > size))
	{
		if(size > (QuickBufferSize - 1)) //"-1" for reserved symbol endl
		{
			uint allocSize = 0;
			T* newBuffer = new T[allocSize = ((size / Capacity) + 1) * Capacity];
			if(mBuffer)
			{
				Move(mBuffer, newBuffer, mLength); // copy source
			}
			if(IsUsingQuickBuffer())
			{
				if(mBuffer)
				{
					Clear(); // clear old data this lambada for quick buffer need clear old data
				}
			}
			else
			{
				delete[] mBuffer; // delete old buffer
			}
			mBuffer = newBuffer;
			mSize = allocSize;
		}
		else
		{
			mSize = QuickBufferSize;
			mBuffer = mQuickBuffer;
		}
	}

	mLength = size;
	return mLength;
}

template<typename T, int QuickBufferSize, int Capacity>
inline uint TArrayAllocation<T, QuickBufferSize, Capacity>::Length() const
{
	return mLength;
}

template<typename T, int QuickBufferSize, int Capacity>
inline uint	TArrayAllocation<T, QuickBufferSize, Capacity>::Size() const
{
	return mSize;
}

template<typename T, int QuickBufferSize, int Capacity>
inline bool	TArrayAllocation<T, QuickBufferSize, Capacity>::Empty() const
{
	return mLength == 0;
}

/*-------------------------------------------------------------------------
| Array:
---------------------------------------------------------------------------*/
template<typename T, typename TStrategy>
TArray<T, TStrategy>::TArray(void) : TStrategy()
{
	Base::SetLength(Base::QuickBufferSize);
	Base::mLength = 0;
}
